package org.feichao.xdao.util;

import org.apache.commons.lang.StringUtils;
import org.feichao.xdao.annotations.MethodName;
import org.feichao.xdao.util.expression.AbstractMethod;
import org.feichao.xdao.util.expression.CurrentTimeMillisMethod;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 表达式工具
 *
 * @author chao
 * @since 2015/5/27
 */
public class ExpressionUtil {

    private static final Map<String, AbstractMethod> methods = new HashMap<String, AbstractMethod>();

    /**
     * 注册方法
     * @param method
     */
    public static void registerMethod(AbstractMethod method){
        String methodName = method.getClass().getName();
        MethodName methodNameAnno = method.getClass().getAnnotation(MethodName.class);
        if(methodNameAnno != null){
            String s = methodNameAnno.value();
            if(StringUtils.isNotEmpty(s)){
                methodName = s;
            }
        }
        methods.put(methodName, method);
    }

    static {
        //默认提供now
        registerMethod(new CurrentTimeMillisMethod());
    }


    /**
     * 获取表达式结果
     *
     * @param params
     * @param expressionStr
     * @return
     */
    public static Object get(Map<String, Object> params, String expressionStr){
        expressionStr = StringUtils.trimToEmpty(expressionStr);

        if(expressionStr.startsWith("#")){ //METHOD
            String methodName = StringUtils.substring(expressionStr, 1);
            AbstractMethod method = methods.get(methodName);
            if(method == null){
                throw new RuntimeException("Cannot find method:" + methodName);
            }
            return method.invoke();
        }else if(expressionStr.indexOf('.') > -1){
            String[] words = expressionStr.split("\\.");
            String objectName = words[0];
            String objectField = words[1];
            Object obj = params.get(objectName);
            if(obj == null){
                throw new RuntimeException("Cannot run expression:" + expressionStr);
            }
            return FieldAccessUtil.getter(obj, objectField);
        }else{
            return params.get(expressionStr);
        }
    }
}
